package com.ltg.urban.domain.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltg.framework.error.exception.BaseException;
import com.ltg.framework.mybatis.entities.BaseEntity;
import com.ltg.framework.util.http.PageInfo;
import com.ltg.framework.util.http.Result;
import com.ltg.urban.domain.file.entity.FileInfo;
import com.ltg.urban.domain.file.service.FileInfoService;
import com.ltg.urban.domain.project.data.request.*;
import com.ltg.urban.domain.project.data.response.ProjectDetailResp;
import com.ltg.urban.domain.project.data.response.ProjectPageResp;
import com.ltg.urban.domain.project.entity.*;
import com.ltg.urban.domain.project.mapper.*;
import com.ltg.urban.domain.project.service.UrbanProjectService;
import com.ltg.urban.domain.project.service.UrbanProjectUserService;
import com.ltg.urban.domain.sys.data.response.CurrentUserHolder;
import com.ltg.urban.domain.sys.data.response.UserInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * <p> ClassName: UrbanProjectServiceImpl </p>
 * <p> Package: com.ltg.urban.domain.project.service.impl </p>
 * <p> Description: </p>
 * <p></p>
 *
 * @Author: LTG
 * @Create: 2023/2/22 - 21:50
 * @Version: v1.0
 */
@Service
@RequiredArgsConstructor
public class UrbanProjectServiceImpl extends ServiceImpl<UrbanProjectMapper, UrbanProject> implements UrbanProjectService {

    private final UrbanProjectMapper urbanProjectMapper;
    private final UrbanProjectCapitalMapper urbanProjectCapitalMapper;
    private final UrbanProjectCapitalDetailMapper urbanProjectCapitalDetailMapper;
    private final UrbanProjectUserMapper urbanProjectUserMapper;
    private final UrbanProjectRecordMapper urbanProjectRecordMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProject> apply(@RequestBody ApplyProjectReq req) {
        //生成项目
        UrbanProject urbanProject = UrbanProject.builder()
                .projectName(req.getProjectName())
                .budgetTime(req.getBudgetTime())
                .mangerId(req.getMangerId())
                .status(ProjectStatusEnum.PROJECT_START.getStatus())
                .approveResult(0)
                .content(req.getContent())
                .fileId(req.getFileId())
                .build();
        urbanProjectMapper.insert(urbanProject);
        //项目记录
        UrbanProjectRecord projectRecord = UrbanProjectRecord.builder()
                .projectId(urbanProject.getId())
                .status(ProjectStatusEnum.PROJECT_START.getStatus())
                .statusDescription(ProjectStatusEnum.PROJECT_START.getStatusDescription())
                .build();
        urbanProjectRecordMapper.insert(projectRecord);
        //项目负责人
        UrbanProjectUser mangerUser = UrbanProjectUser.builder()
                .projectId(urbanProject.getId())
                .userId(req.getMangerId())
                .position(ProjectPositionEnum.PROJECT_MANAGER.getName())
                .build();
        urbanProjectUserMapper.insert(mangerUser);

        //生成资金
        UrbanProjectCapital urbanProjectCapital = UrbanProjectCapital.builder()
                .projectId(urbanProject.getId())
                .budgetCost(req.getBudgetCost())
                .actualCost(BigDecimal.ZERO)
                .approveResult(0)
                .build();
        urbanProjectCapitalMapper.insert(urbanProjectCapital);
        return Result.success(urbanProject);
    }


    private final FileInfoService fileInfoService;

    @Override
    public PageInfo<ProjectPageResp> pageList(UserInfo userInfo, Page<ProjectPageResp> page, Integer status, Integer approveResult,String projectName) {
        page = urbanProjectMapper.pageList(page, userInfo.getUser().getId(), userInfo.getRole().getRoleName(), status, approveResult,projectName);
        for (ProjectPageResp details : page.getRecords()) {
            details.setFileUrl(fileInfoService.getFileUrl(details.getFileId()));
        }
        return new PageInfo<>(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProject> modify(Long projectId, ApplyProjectReq req) {
        UrbanProject urbanProject = urbanProjectMapper.selectById(projectId);
        urbanProject.setProjectName(req.getProjectName());
        urbanProject.setMangerId(req.getMangerId());
        urbanProject.setBudgetTime(req.getBudgetTime());
        urbanProject.setContent(req.getContent());
        urbanProjectMapper.updateById(urbanProject);

        UrbanProjectCapital urbanProjectCapital = urbanProjectCapitalMapper.selectByProjectId(projectId);
        urbanProjectCapital.setBudgetCost(req.getBudgetCost());
        urbanProjectCapitalMapper.updateById(urbanProjectCapital);
        return Result.success(urbanProject);
    }

    private final UrbanProjectUserService urbanProjectUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> modifyUser(Long projectId, List<ProjectPosition> member) {
        LambdaQueryWrapper<UrbanProjectUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UrbanProjectUser::getProjectId, projectId);
        List<UrbanProjectUser> users = urbanProjectUserMapper.selectList(wrapper);
        List<UrbanProjectUser> createList = new LinkedList<>();
        if (users.isEmpty()) {
            for (ProjectPosition position : member) {
                UrbanProjectUser projectUser = UrbanProjectUser
                        .builder()
                        .projectId(projectId)
                        .position(position.getPosition())
                        .userId(position.getUserId())
                        .build();
                createList.add(projectUser);
            }
        } else {
            List<Long> userIds = new LinkedList<>(users.stream().map(BaseEntity::getId).toList());
            for (ProjectPosition position : member) {
                if (!userIds.contains(position.getUserId())) {
                    UrbanProjectUser projectUser = UrbanProjectUser
                            .builder()
                            .projectId(projectId)
                            .position(position.getPosition())
                            .userId(position.getUserId())
                            .build();
                    createList.add(projectUser);
                } else {
                    userIds.remove(position.getUserId());
                }
            }
            if (!userIds.isEmpty()) {
                urbanProjectUserService.removeBatchByIds(userIds);
            }
        }
        if (!createList.isEmpty()) {
            urbanProjectUserService.saveBatch(createList);
        }
        //该删除的
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProjectUser> addProjectUser(Long projectId, ProjectPosition member) {
        LambdaQueryWrapper<UrbanProjectUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UrbanProjectUser::getProjectId, projectId);
        wrapper.eq(UrbanProjectUser::getUserId, member.getUserId());
        boolean exists = urbanProjectUserMapper.exists(wrapper);
        if (exists) {
            throw new BaseException("项目人员不能重复添加");
        }
        UrbanProjectUser urbanProjectUser = UrbanProjectUser.builder()
                .projectId(projectId)
                .userId(member.getUserId())
                .position(member.getPosition())
                .build();
        urbanProjectUserService.save(urbanProjectUser);
        return Result.success(urbanProjectUser);
    }

    @Override
    public Result<Void> deleteProjectUser(Long projectId, Long userId) {
        urbanProjectUserMapper.deleteUser(projectId, userId);
        return Result.success();
    }

    @Override
    public Result<ProjectDetailResp> projectDetail(Long projectId) {
        UrbanProject urbanProject = urbanProjectMapper.selectByProjectId(projectId);
        FileInfo fileInfo = fileInfoService.getById(urbanProject.getFileId());
        urbanProject.setFileInfo(fileInfo);
        ProjectDetailResp projectDetailResp = new ProjectDetailResp();
        projectDetailResp.setUrbanProject(urbanProject);
        List<UrbanProjectRecord> urbanProjectRecords = urbanProjectRecordMapper.selectList(new LambdaQueryWrapper<UrbanProjectRecord>().eq(UrbanProjectRecord::getProjectId, projectId));
        projectDetailResp.setRecords(urbanProjectRecords);
        List<UrbanProjectUser> users = urbanProjectUserMapper.selectByProjectId(projectId);
        projectDetailResp.setUsers(users);
        return Result.success(projectDetailResp);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProject> projectChangeStatus(Long projectId, ModifyProjectStatusReq req) {

        UrbanProject urbanProject = urbanProjectMapper.selectById(projectId);
        UrbanProjectRecord projectRecord = UrbanProjectRecord.builder()
                .projectId(projectId)
                .content(req.getContent())
                .build();
        switch (req.getStatus()) {
            //送审
            case 1 -> {
                urbanProject.setStatus(ProjectStatusEnum.APPROVAL_START.getStatus());
                projectRecord.setStatus(ProjectStatusEnum.APPROVAL_START.getStatus());
                projectRecord.setStatusDescription(ProjectStatusEnum.APPROVAL_START.getStatusDescription());
            }
            //开工
            case 2 -> {
                urbanProject.setStatus(ProjectStatusEnum.PROJECT_RUN.getStatus());
                urbanProject.setStartTime(LocalDateTime.now());
                projectRecord.setStatus(ProjectStatusEnum.PROJECT_RUN.getStatus());
                projectRecord.setStatusDescription(ProjectStatusEnum.PROJECT_RUN.getStatusDescription());
            }
            //完结
            case 3 -> {
                urbanProject.setStatus(ProjectStatusEnum.PROJECT_ACCEPTANCE.getStatus());
                urbanProject.setEndTime(LocalDateTime.now());
                urbanProject.setActualTime(urbanProject.getStartTime().getMonth().getValue() - LocalDateTime.now().getMonth().getValue());
                projectRecord.setStatus(ProjectStatusEnum.PROJECT_ACCEPTANCE.getStatus());
                projectRecord.setStatusDescription(ProjectStatusEnum.PROJECT_ACCEPTANCE.getStatusDescription());
            }
            //完工
            case 5 -> {
                urbanProject.setStatus(ProjectStatusEnum.PROJECT_FINISH.getStatus());
                projectRecord.setStatus(ProjectStatusEnum.PROJECT_FINISH.getStatus());
                projectRecord.setStatusDescription(ProjectStatusEnum.PROJECT_FINISH.getStatusDescription());
            }
            default -> throw new BaseException("传惨错误");
        }
        urbanProjectMapper.updateById(urbanProject);
        urbanProjectRecordMapper.insert(projectRecord);
        return Result.success(urbanProject);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProject> projectApprove(Long projectId, ApproveProjectReq req) {
        UrbanProjectRecord urbanProjectRecord = UrbanProjectRecord.builder().projectId(projectId).content(req.getContent())
                .build();
        UrbanProject urbanProject = urbanProjectMapper.selectById(projectId);
        UrbanProjectCapital urbanProjectCapital = urbanProjectCapitalMapper.selectByProjectId(projectId);
        urbanProject.setApprover(req.getApprover());
        if (req.getApproveResult().equals(1)) {
            //同意
            urbanProject.setStatus(ProjectStatusEnum.APPROVAL_FINISH.getStatus());
            urbanProject.setApproveTime(LocalDateTime.now());
            urbanProject.setApproveResult(req.getApproveResult());
            urbanProjectCapital.setApproveResult(req.getApproveResult());
            urbanProjectRecord.setStatus(ProjectStatusEnum.APPROVAL_FINISH.getStatus());
            urbanProjectRecord.setStatusDescription("验收成功");
        } else {
            //不同意
            urbanProject.setStatus(ProjectStatusEnum.PROJECT_START.getStatus());
            urbanProject.setApproveTime(LocalDateTime.now());
            urbanProject.setApproveResult(req.getApproveResult());
            urbanProjectRecord.setStatus(ProjectStatusEnum.PROJECT_START.getStatus());
            urbanProjectCapital.setApproveResult(req.getApproveResult());
            urbanProjectRecord.setStatusDescription("验收失败");
        }
        urbanProjectMapper.updateById(urbanProject);
        urbanProjectCapitalMapper.updateById(urbanProjectCapital);
        urbanProjectRecordMapper.insert(urbanProjectRecord);
        return Result.success(urbanProject);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<UrbanProject> anewApply(Long projectId, AnewApplyReq req) {
        UrbanProject urbanProject = urbanProjectMapper.selectById(projectId);
        urbanProject.setApproveResult(0);
        urbanProject.setStatus(ProjectStatusEnum.APPROVAL_START.getStatus());
        urbanProjectMapper.updateById(urbanProject);
        UrbanProjectRecord projectRecord = UrbanProjectRecord.builder()
                .status(1)
                .content(req.getContent())
                .projectId(projectId)
                .statusDescription("重新申请")
                .build();
        urbanProjectRecordMapper.insert(projectRecord);
        return Result.success(urbanProject);
    }


}
